#pragma once
#include <string>
#include <array>
#include <vector>
#include <map>
#include <simple_enum.hpp>
#include <cereal/archives/binary.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/array.hpp>
#include <cereal/types/map.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/archives/json.hpp>










enum class ObstacleType: int8_t
{
    Automobile = 0,
    Pedestrian = 1,
    Truck = 2,
};


namespace simple_enum
{
namespace enum_details
{
        template <>
        inline constexpr auto names_v<ObstacleType> = std::array<std::string_view, 3>{
            "Automobile",
            "Pedestrian",
            "Truck",
        };

        template <>
        inline constexpr auto values_v<ObstacleType> = std::array<int8_t, 3>{
            0,
            1,
            2,
        };

        template <>
        inline constexpr auto entries_v<ObstacleType> = std::array<std::pair<std::string_view, int8_t>, 3>{
            std::pair<std::string_view, int8_t>("Automobile", 0),
            std::pair<std::string_view, int8_t>("Pedestrian", 1),
            std::pair<std::string_view, int8_t>("Truck", 2),
        };
} // namespace enum_details
} // namespace simple_enum

namespace cereal {
template <class Archive> inline
std::string save_minimal( Archive const &, ObstacleType const & t )
{
    std::string str(simple_enum::enum_name<ObstacleType>(t));
    return str;
}

template <class Archive> inline
void load_minimal( Archive const &, ObstacleType & t, std::string const & value )
{
    std::string_view sv(value);
    t = simple_enum::enum_cast<ObstacleType>(sv).value();
}
} // namespace cereal


struct Vec3f
{
    float x{};
    float y{};
    float z{};
};


template<class Archive>
void serialize(Archive& archive,
               Vec3f& m) {
    archive(cereal::make_nvp("x", m.x));
    archive(cereal::make_nvp("y", m.y));
    archive(cereal::make_nvp("z", m.z));
}


struct Quat4f
{
    float x{};
    float y{};
    float z{};
    float w{};
};


template<class Archive>
void serialize(Archive& archive,
               Quat4f& m) {
    archive(cereal::make_nvp("x", m.x));
    archive(cereal::make_nvp("y", m.y));
    archive(cereal::make_nvp("z", m.z));
    archive(cereal::make_nvp("w", m.w));
}


struct Pose3f
{
    Vec3f position{};
    Quat4f orientation{};
};


template<class Archive>
void serialize(Archive& archive,
               Pose3f& m) {
    archive(cereal::make_nvp("position", m.position));
    archive(cereal::make_nvp("orientation", m.orientation));
}


class Trajectory
{
public:

    Trajectory(std::vector<Pose3f> poses, std::vector<int64_t> timestamps, Pose3f reference_frame)
        : m_poses(std::move(poses)),m_timestamps(std::move(timestamps)),m_reference_frame(std::move(reference_frame)){}
    // 默认构造函数 default constructor
    Trajectory() = default;
    // 拷贝构造函数 copy constructor
    Trajectory(const Trajectory&) = default;
    // 移动构造函数 move constructor
    Trajectory(Trajectory&&) = default;
    // 拷贝赋值运算符 copy assignment operator
    Trajectory& operator=(const Trajectory&) = default;
    // 移动赋值运算符 move assignment operator
    Trajectory& operator=(Trajectory&&) noexcept = default;
    // 析构函数 destructor
    ~Trajectory() = default; 
    
    inline const std::vector<Pose3f> & get_poses() const { return m_poses; }
    inline std::vector<Pose3f>& get_poses_mutable() { return m_poses; }
    inline void set_poses(std::vector<Pose3f> poses) { m_poses = std::move(poses); }

    inline const std::vector<int64_t> & get_timestamps() const { return m_timestamps; }
    inline std::vector<int64_t>& get_timestamps_mutable() { return m_timestamps; }
    inline void set_timestamps(std::vector<int64_t> timestamps) { m_timestamps = std::move(timestamps); }

    inline const Pose3f & get_reference_frame() const { return m_reference_frame; }
    inline Pose3f& get_reference_frame_mutable() { return m_reference_frame; }
    inline void set_reference_frame(Pose3f reference_frame) { m_reference_frame = std::move(reference_frame); }


    template<class Archive>
    void serialize(Archive& archive) {
        archive(cereal::make_nvp("poses", m_poses));
        archive(cereal::make_nvp("timestamps", m_timestamps));
        archive(cereal::make_nvp("reference_frame", m_reference_frame));
    }

private:
    std::vector<Pose3f> m_poses{};
    std::vector<int64_t> m_timestamps{};
    Pose3f m_reference_frame{};
};




class Obstacle
{
public:

    Obstacle(ObstacleType type, int64_t uuid, Trajectory trajectory)
        : m_type(std::move(type)),m_uuid(uuid),m_trajectory(std::move(trajectory)){}
    // 默认构造函数 default constructor
    Obstacle() = default;
    // 拷贝构造函数 copy constructor
    Obstacle(const Obstacle&) = default;
    // 移动构造函数 move constructor
    Obstacle(Obstacle&&) = default;
    // 拷贝赋值运算符 copy assignment operator
    Obstacle& operator=(const Obstacle&) = default;
    // 移动赋值运算符 move assignment operator
    Obstacle& operator=(Obstacle&&) noexcept = default;
    // 析构函数 destructor
    ~Obstacle() = default; 
    
    inline const ObstacleType & get_type() const { return m_type; }
    inline ObstacleType& get_type_mutable() { return m_type; }
    inline void set_type(ObstacleType type) { m_type = std::move(type); }

    inline int64_t get_uuid() const { return m_uuid; }
    inline int64_t& get_uuid_mutable() { return m_uuid; }
    inline void set_uuid(int64_t uuid) { m_uuid = uuid; }

    inline const Trajectory & get_trajectory() const { return m_trajectory; }
    inline Trajectory& get_trajectory_mutable() { return m_trajectory; }
    inline void set_trajectory(Trajectory trajectory) { m_trajectory = std::move(trajectory); }


    template<class Archive>
    void serialize(Archive& archive) {
        archive(cereal::make_nvp("type", m_type));
        archive(cereal::make_nvp("uuid", m_uuid));
        archive(cereal::make_nvp("trajectory", m_trajectory));
    }

private:
    ObstacleType m_type{};
    int64_t m_uuid{};
    Trajectory m_trajectory{};
};





